package com.tanhua.server.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.PageUtil;
import com.github.tobato.fastdfs.domain.conn.FdfsWebServer;
import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import com.tanhua.autoconfig.template.OssTemplate;
import com.tanhua.commons.utils.Constants;
import com.tanhua.dubbo.api.UserInfoApi;
import com.tanhua.dubbo.api.VideoApi;
import com.tanhua.dubbo.api.VideoCommentApi;
import com.tanhua.model.domain.UserInfo;
import com.tanhua.model.enums.CommentType;
import com.tanhua.model.mongo.UserFocus;
import com.tanhua.model.mongo.Video;
import com.tanhua.model.mongo.VideoComment;
import com.tanhua.model.mongo.VideoCommentLike;
import com.tanhua.model.vo.ErrorResult;
import com.tanhua.model.vo.PageResult;
import com.tanhua.model.vo.VideoCommentVo;
import com.tanhua.model.vo.VideoVo;
import com.tanhua.server.exception.BusinessException;
import com.tanhua.server.interceptor.UserHolder;
import org.apache.dubbo.config.annotation.DubboReference;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class SmallVideosService {

    @Autowired
    private FastFileStorageClient client;

    @Autowired
    private FdfsWebServer webServer;

    @Autowired
    private OssTemplate ossTemplate;

    @DubboReference
    private VideoApi videoApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    @DubboReference
    private VideoCommentApi videoCommentApi;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @Autowired
    private MqMessageService mqMessageService;

    /**
     * 上传视频
     * @param videoThumbnail 封面图片文件
     * @param videoFile  视频文件
     */
    @CacheEvict(value="videos",allEntries = true)  //清空缓存
    public void saveVideos(MultipartFile videoThumbnail, MultipartFile videoFile) throws IOException {

        if(videoFile.isEmpty() || videoThumbnail.isEmpty()) {
            throw new BusinessException(ErrorResult.error());
        }

        //1、将视频上传到FastDFS,获取访问URL
        String filename = videoFile.getOriginalFilename();  // abc.mp4
        filename = filename.substring(filename.lastIndexOf(".")+1);
        StorePath storePath = client.uploadFile(videoFile.getInputStream(), videoFile.getSize(), filename, null);
        String videoUrl = webServer.getWebServerUrl() + storePath.getFullPath();
        //2、将封面图片上传到阿里云OSS，获取访问的URL
        String imageUrl = ossTemplate.upload(videoThumbnail.getOriginalFilename(), videoThumbnail.getInputStream());
        //3、构建Videos对象
        Video video = new Video();
        video.setUserId(UserHolder.getUserId());
        video.setPicUrl(imageUrl);
        video.setVideoUrl(videoUrl);
        video.setText("我就是我，不一样的烟火");
        //4、调用API保存数据
        String videoId = videoApi.save(video);
        if(StringUtils.isEmpty(videoId)) {
            throw new BusinessException(ErrorResult.error());
        }

        //发送消息
        mqMessageService.sendLogMessage(UserHolder.getUserId(),"0301","video",videoId);
    }

    //查询视频列表
    @Cacheable(
            value="videos",
            key = "T(com.tanhua.server.interceptor.UserHolder).getUserId()+'_'+#page+'_'+#pagesize")  //userid _ page_pagesize
    public PageResult queryVideoList(Integer page, Integer pagesize) {

        //1、查询redis数据
        String redisKey = Constants.VIDEOS_RECOMMEND +UserHolder.getUserId();
        String redisValue = redisTemplate.opsForValue().get(redisKey);
        //2、判断redis数据是否存在，判断redis中数据是否满足本次分页条数
        List<Video> list = new ArrayList<>();
        int redisPages = 0;
        if(!StringUtils.isEmpty(redisValue)) {
            //3、如果redis数据存在，根据VID查询数据
            String[] values = redisValue.split(",");
            //判断当前页的起始条数是否小于数组总数
            if( (page -1) * pagesize < values.length) {
                List<Long> vids = Arrays.stream(values).skip((page - 1) * pagesize).limit(pagesize)
                        .map(e->Long.valueOf(e))
                        .collect(Collectors.toList());
                //5、调用API根据PID数组查询动态数据
                list = videoApi.findMovementsByVids(vids);
            }
            redisPages = PageUtil.totalPage(values.length,pagesize);
        }
        //4、如果redis数据不存在，分页查询视频数据
        if(list.isEmpty()) {
            //page的计算规则，  传入的页码  -- redis查询的总页数
            list = videoApi.queryVideoList(page - redisPages, pagesize);  //page=1 ?
        }
        //5、提取视频列表中所有的用户id
        List<Long> userIds = CollUtil.getFieldValues(list, "userId", Long.class);
        //6、查询用户信息
        Map<Long, UserInfo> map = userInfoApi.findByIds(userIds, null);
        //7、构建返回值
        List<VideoVo> vos = new ArrayList<>();
        for (Video video : list) {
            UserInfo info = map.get(video.getUserId());
            if(info != null) {
                VideoVo vo = VideoVo.init(info, video);
                /*//调用api查询当前登录用户是否已关注当前视频用户
                Boolean focus = videoApi.isFocus(UserHolder.getUserId(), vo.getUserId());*/
                //从Redis中查询是否关注该用户
                String key = Constants.FOCUS_USER_KEY + UserHolder.getUserId();
                String hashKey = Constants.FOCUS_HASH_KEY + video.getUserId();
                Boolean hasKey = redisTemplate.opsForHash().hasKey(key, hashKey);
                if(hasKey){
                    vo.setHasFocus(1);
                }else {
                    vo.setHasFocus(0);
                }
               /* //查询当前用户是否已点赞该视频，并设置对应的属性值
                Boolean hasLike = videoCommentApi.hasLike(UserHolder.getUserId(),new ObjectId(vo.getId()));*/
                //从Redis中查询是否点赞该小视频
                String vkey = Constants.VIDEO_INTERACT_KEY + UserHolder.getUserId();
                String vhashKey = Constants.VIDEO_LIKE_HASHKEY + vo.getId();
                Boolean aBoolean = redisTemplate.opsForHash().hasKey(vkey, vhashKey);
                if(aBoolean){
                    vo.setHasLiked(1);
                }else{
                    vo.setHasLiked(0);
                }
                //调用api查询该条小视频评论数量
                Long commentCount = videoCommentApi.commentCount(vo.getId());
                vo.setCommentCount(Math.toIntExact(commentCount));
                vos.add(vo);
            }
        }
        return new PageResult(page,pagesize,0l,vos);
    }

    /*
     * 视频点赞
     * @param videoId
     */
    @CacheEvict(value="videos",allEntries = true)  //清空缓存
    public Integer videoLike(String videoId) {
        //1.调用api查询用户是否已点赞
        Boolean hasComment = videoCommentApi.hasComment(videoId,UserHolder.getUserId(),CommentType.LIKE);
        if(hasComment){
            throw new BusinessException(ErrorResult.likeError());
        }
        //3.调用api保存数据到MongoDB
        VideoComment videoComment = new VideoComment();
        videoComment.setVideoId(new ObjectId(videoId));
        videoComment.setCommentType(CommentType.LIKE.getType());
        videoComment.setUserId(UserHolder.getUserId());
        videoComment.setCreated(System.currentTimeMillis());
        //保存videoCommnet数据，修改video表中对应数据
        Integer count = videoCommentApi.save(videoComment);
        //拼接Redis的key，将用户的点赞状态存入Redis
        String key = Constants.VIDEO_INTERACT_KEY + UserHolder.getUserId();
        String hashKey = Constants.VIDEO_LIKE_HASHKEY + videoId;
        redisTemplate.opsForHash().put(key,hashKey,"1");
        //删除Redis中的视频列表数据

        return Math.toIntExact(count);
    }

    //取消视频点赞
    @CacheEvict(value="videos",allEntries = true)  //清空缓存
    public Integer videoDisLike(String videoId) {
        //1.调用api查询用户是有已点赞
        Boolean hasComment = videoCommentApi.hasComment(videoId, UserHolder.getUserId(), CommentType.LIKE);
        if(!hasComment){
            //视频未点赞，抛出异常
            throw new BusinessException(ErrorResult.disLikeError()) ;
        }
        //调用pai删除点赞数据，返回点赞数量
        VideoComment videoComment = new VideoComment();
        videoComment.setVideoId(new ObjectId(videoId));
        videoComment.setCommentType(CommentType.LIKE.getType());
        videoComment.setUserId(UserHolder.getUserId());
        Integer count = videoCommentApi.delete(videoComment);
        //4、拼接redis的key，删除点赞状态
        String key = Constants.VIDEO_INTERACT_KEY + UserHolder.getUserId();
        String hashKey = Constants.VIDEO_LIKE_HASHKEY + videoId;
        redisTemplate.opsForHash().delete(key,hashKey);
        return count;
    }

    //分页查询小视频评论列表
    @Cacheable(
            value = "videoComments",
            key = "#videoId+'_'+#page+'_'+#ppagesize"
    )
    //取消视频点赞
    @CacheEvict(value="videos",allEntries = true)  //清空缓存
    public PageResult findComments(ObjectId videoId, Integer page, Integer pagesize) {
        //1.调用api查询评论列表
        List<VideoComment> videoCommentsList = videoApi.findComments(videoId, CommentType.COMMENT,page,pagesize);
        //2.判断list集合是否存在
        if(CollUtil.isEmpty(videoCommentsList)){
            //不存在，返回一个空的pageResult
            return new PageResult();
        }
        //3.提取所有的用户id，调用userApi查询用户详情
        List<Long> userIds = CollUtil.getFieldValues(videoCommentsList,"userId",Long.class);
        Map<Long, UserInfo> userInfoMap = userInfoApi.findByIds(userIds, null);
        //4.构造vo对象
        List<VideoCommentVo> vos = new ArrayList<>();
        for (VideoComment videoComment : videoCommentsList) {
            UserInfo userInfo = userInfoMap.get(videoComment.getUserId());
            if(userInfo != null){
                VideoCommentVo vo = VideoCommentVo.init(userInfo, videoComment);
                /*//调用papi查询videoCommentLike表，判断是否点赞该条评论
                Boolean hasLikeComment = videoCommentApi.hasLikeComment(UserHolder.getUserId(), vo.getId());*/
                //从Redis中查询当前用户是否点赞该条评论
                String key = Constants.VIDEO_RECOMMEND_LIKE + UserHolder.getUserId();
                String hashKey = Constants.VIDEOCOMMENT_LIKE_HASHKEY + vo.getId();
                String res = (String) redisTemplate.opsForHash().get(key, hashKey);
                if(res == null || "".equals(res)){
                    vo.setHasLiked(0);
                }else{
                    vo.setHasLiked(1);
                }
                vos.add(vo);
            }
        }
        return new PageResult(page,pagesize,0L,vos);
    }

    //发布小视频评论
    @CacheEvict(value = {"videoComments","videos"},allEntries = true)
    public Integer publishComment(String videoId, String commentTxt) {
        //1.获取当前用户id
        Long userId = UserHolder.getUserId();
        //2.构造videoComment
        VideoComment videoComment = new VideoComment();
        videoComment.setVideoId(new ObjectId(videoId));
        videoComment.setCommentType(CommentType.COMMENT.getType());
        videoComment.setContent(commentTxt);
        videoComment.setUserId(UserHolder.getUserId());
        videoComment.setCreated(System.currentTimeMillis());
        //3.调用pai保存评论
        Integer count = videoCommentApi.save(videoComment);
        return count;
    }

    //小视频评论点赞
    @CacheEvict(value = "videoComments",allEntries = true)
    public Integer videoCommentLike(String videoCommentId) {
        //1.获取当前操作用户
        Long userId = UserHolder.getUserId();
        //2.调用api查询当前用户是否点赞该条评论
        Boolean hasLike = videoCommentApi.hasLikeComment(userId,videoCommentId);
        if(hasLike){
            //已经点赞，抛出异常‘
            throw new BusinessException(ErrorResult.likeError());
        }
        //未点赞,保存点赞数据
        VideoCommentLike videoCommentLike = new VideoCommentLike();
        videoCommentLike.setUserId(userId);
        videoCommentLike.setVideoCommentId(new ObjectId(videoCommentId));
        videoCommentLike.setCreated(System.currentTimeMillis());
        //调用api
        Integer count = videoCommentApi.saveLikeComment(videoCommentLike);
        //拼接redis的key，将用户的点赞状态存入Redis
        String key = Constants.VIDEO_RECOMMEND_LIKE + UserHolder.getUserId();
        String hashKey = Constants.VIDEOCOMMENT_LIKE_HASHKEY + videoCommentId;
        redisTemplate.opsForHash().put(key,hashKey,"1");
        return count;
    }

    //取消小视频评论点赞
    @CacheEvict(value = "videoComments",allEntries = true)
    public Integer videoCommentDislike(String videoCommentId) {
        //获取当前操作用户
        Long userId = UserHolder.getUserId();
        //查询videoCommentLike表，判断用户是否已点赞该条评论
        Boolean hasLike = videoCommentApi.hasLikeComment(userId, videoCommentId);
        if(!hasLike){
            //未点赞，抛出异常
            throw new BusinessException(ErrorResult.disLikeError());
        }
        //已点赞，删除videoCommentLike表中的数据,//修改videoComment表中的likeCount
        VideoCommentLike videoCommentLike = new VideoCommentLike();
        videoCommentLike.setVideoCommentId(new ObjectId(videoCommentId));
        videoCommentLike.setUserId(userId);
        Integer likeCount = videoCommentApi.deleteCommentLike(videoCommentLike);
        //删除Redis中的数据
        String key = Constants.VIDEO_RECOMMEND_LIKE + UserHolder.getUserId();
        String hashKey = Constants.VIDEOCOMMENT_LIKE_HASHKEY + videoCommentId;
        redisTemplate.opsForHash().delete(key,hashKey);
        //返回likecount
        return likeCount;
    }

    //视频用户关注
    @CacheEvict(value="videos",allEntries = true)  //清空缓存
    public Long userFocus(Long uid) {
        //获取当前用户id
        Long userId = UserHolder.getUserId();
        //查询focusUser表，判断当前用户是否已关注该用户
        Boolean isFocus = videoApi.isFocus(userId,uid);
        if(isFocus){
            //已关注，抛出异常
            throw new BusinessException(ErrorResult.hasFocus());
        }
        //未关注，保存关注数据
        UserFocus userFocus = new UserFocus();
        userFocus.setUserId(userId);
        userFocus.setFocusUserId(uid);
        userFocus.setCreated(System.currentTimeMillis());
        //调用api保存
        Long focusCount = videoApi.focusUser(userFocus);
        //拼接Redis的key，将用户的关注状态存入Redis
        String key = Constants.FOCUS_USER_KEY + UserHolder.getUserId();
        String hashKey = Constants.FOCUS_HASH_KEY + uid;
        redisTemplate.opsForHash().put(key,hashKey,"1");
        return focusCount;
    }

    //视频用户取消关注
    @CacheEvict(value="videos",allEntries = true)  //清空缓存
    public Long  userUnFocus(Long uid) {
        //获取当前用户id
        Long userId = UserHolder.getUserId();
        //查询focusUser表，判断当前用户是否已关注该用户
        Boolean isFocus = videoApi.isFocus(userId,uid);
        if(!isFocus){
            //未关注，抛出异常
            throw new BusinessException(ErrorResult.hasFocus());
        }
        //已关注，删除focusUser表中的数据
        UserFocus userFocus = new UserFocus();
        userFocus.setUserId(userId);
        userFocus.setFocusUserId(uid);
        userFocus.setCreated(System.currentTimeMillis());
        //调用api删除
        Long focusCount = videoApi.unFocusUser(userFocus);
        //删除Redis中的数据
        String key = Constants.FOCUS_USER_KEY + UserHolder.getUserId();
        String hashKey = Constants.FOCUS_HASH_KEY + uid;
        redisTemplate.opsForHash().delete(key,hashKey);
        return focusCount;
    }
}
